<?php

/**
 *
 * @description: 支付相关接口的数据基类
 */

namespace Payment\Common;

use Payment\Config;
use Payment\Utils\ArrayUtil;

/**
 * Class BaseData
 * 支付相关接口的数据基类
 * @package Payment\Common\Sw\Data
 *
 */
abstract class BaseData
{

    /**
     * 支付的请求数据
     * @var array $data
     */
    protected $data;

    /**
     * 支付返回的数据
     * @var array $retData
     */
    protected $retData;

    /**
     * 配置类型
     * @var string $configType
     */
    protected $channel;

    /**
     * BaseData constructor.
     * @param ConfigInterface $config
     * @param array $reqData
     * @throws PayException
     */
    public function __construct(ConfigInterface $config, array $reqData)
    {
        if ($config instanceof WxConfig) {
            $this->channel = Config::WECHAT_PAY;
        } elseif ($config instanceof AliConfig) {
            $this->channel = Config::ALI_PAY;
        } elseif ($config instanceof CmbConfig) {
            $this->channel = Config::CMB_PAY;
        } elseif ($config instanceof TLConfig) {
            $this->channel = Config::TL_PAY;
        } elseif ($config instanceof MiConfig) {
            $this->channel = Config::MI_PAY;
        } elseif ($config instanceof SwConfig) {
            $this->channel = Config::SW_PAY;
        } elseif ($config instanceof FuConfig) {
            $this->channel = Config::FU_PAY;
        } elseif ($config instanceof LTFConfig) {
			$this->channel = Config::LTF_PAY;
		} elseif ($config instanceof YSConfig) {
            $this->channel = Config::YS_PAY;
        }elseif ($config instanceof YSEConfig) {
            $this->channel = Config::YSE_PAY;
        }elseif ($config instanceof SwThreeConfig) {
            $this->channel = Config::SW_T_PAY;
        }elseif ($config instanceof WnfConfig) {
            $this->channel = Config::WNF_PAY;
        }elseif ($config instanceof HsqConfig) {
            $this->channel = Config::HSQ_PAY;
        }elseif ($config instanceof HsqTransConfig) {
            $this->channel = Config::BAOFOO_PAY;
            $tmp = $reqData;unset($reqData);$reqData['reqData'] = $tmp;
        }
        $this->data = array_merge($config->toArray(), $reqData);//配置信息合并
        try {
            $this->checkDataParam();
        } catch (PayException $e) {
            throw $e;
        }
    }

    /**
     * 获取变量，通过魔术方法
     * @param string $name
     * @return null|string
     *
     */
    public function __get($name)
    {
        if (isset($this->data[$name])) {
            return $this->data[$name];
        }

        return null;
    }

    /**
     * 设置变量
     * @param $name
     * @param $value
     *
     */
    public function __set($name, $value)
    {
        $this->data[$name] = $value;
    }

    public function __isset($name)
    {
        if (isset($this->data[$name])) return (false === empty($this->data[$name]));
        return null;
    }

    /**
     * 设置签名
     *
     * @param bool $urlDecode
     * @throws \Exception
     */
    public function setSign(bool $urlDecode = true)
    {
        $this->buildData();
        if ($this->channel === Config::CMB_PAY) {
            $data = $this->retData['reqData'];
        } else {
            if ($this->orgid) {
                $this->retData['orgid'] = $this->orgid;
                $this->retData = ArrayUtil::paraFilter($this->retData);
            }
            $data = $this->retData;
        }

        switch ($this->channel) {
            case Config::TL_PAY:
                $this->retData['sign'] = ArrayUtil::SignArray($data, $this->md5Key); //签名
                break;
            case Config::WNF_PAY:
                $this->makeSign('');
                break;
            case Config::MI_PAY:
                $basePath = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'CacertFile' . DIRECTORY_SEPARATOR;
                $this->cacertPath = "{$basePath}mipay" . DIRECTORY_SEPARATOR . "ldy_private_key.pem";
                $this->retData['sign'] = ArrayUtil::SignRSA($data, $this->cacertPath);//签名
                break;
            case Config::SW_PAY:
                //添加令牌，参数由makesign函数自由控制
                $signData = $this->certainSignData ?? $data;
                $values = ArrayUtil::removeKeys($signData, ['key_sign']);
                if ($this->sign_sort) $values = ArrayUtil::arraySort($values);
                $signStr = ArrayUtil::createLinkstring($values);
                $this->makeSign($signStr);
                break;
            case Config::SW_T_PAY:
                //添加令牌，参数由makesign函数自由控制
                $signData = $this->retData ?? $data;
                $values = ArrayUtil::removeKeys($signData, ['key_sign']);
                $values = ArrayUtil::arraySort($values);
                $signStr = ArrayUtil::createLinkstring($values);
                $this->makeSign($signStr);
                break;
            case Config::FU_PAY:
                $signData = ArrayUtil::arraySort(ArrayUtil::removeKeys(empty($this->certainSignData) ? $data : $this->certainSignData, ['sign']));
                foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_')) unset($signData[$key]);
                $this->retData['sign'] = $this->makeSign(mb_convert_encoding(ArrayUtil::createLinkstring($signData), 'gbk', 'utf-8'));
                unset($signData);
                break;
			case Config::LTF_PAY:
				$signData = $data;
				$values = ArrayUtil::removeKeys($signData, ['sign']);
				$values = ArrayUtil::arraySort($values);
				$signStr = ArrayUtil::createLinkstring($values);
				$this->makeSign($signStr);
				break;
            case Config::YS_PAY:
                $values = ArrayUtil::removeKeys($data, ['sign']);
                $values = ArrayUtil::arraySort($values);
                $signStr = ArrayUtil::createLinkstring($values);
                $this->makeSign($signStr);
                break;
            case Config::YSE_PAY:
                $values = ArrayUtil::removeKeys($data, ['sign']);
                $values = ArrayUtil::arraySort($values);
                $signStr = ArrayUtil::createLinkstring($values);
                $this->makeSign($signStr);
                break;
            case Config::HSQ_PAY:
                $this->retData['sign'] = $this->makeSign(ArrayUtil::createLinkstring($data));
                break;
            case Config::BAOFOO_PAY:
                $this->retData['data_content'] = $this->makeSign($data['data_content']);
                break;
            default:
                $values = ArrayUtil::removeKeys($data, ['sign']);
                $values = ArrayUtil::arraySort($values);
                $signStr = ArrayUtil::createLinkstring($values, $urlDecode);
                $this->retData['sign'] = $this->makeSign($signStr);
        }
    }

    /**
     * 返回处理之后的数据
     * @return array
     *
     */
    public function getData()
    {
        return $this->retData;
    }

    /**
     * 签名算法实现  便于后期扩展微信不同的加密方式
     * @param string $signStr
     * @return string
     */
    abstract protected function makeSign($signStr);

    /**
     * 构建用于支付的签名相关数据
     * @return array
     */
    abstract protected function buildData();

    /**
     * 检查传入的参数. $reqData是否正确.
     * @return mixed
     * @throws PayException
     */
    abstract protected function checkDataParam();
}
